home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Monster Media 1996 #14
/
Monster Media No. 14 (April 1996) (Monster Media, Inc.).ISO
/
prog_d
/
mdboutln.zip
/
MAIN.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1995-11-27
|
20KB
|
547 lines
unit Main;
{ Copyright ⌐ 1995 Maelstrom Software. This program may be freely distributed.
Any code within the program may be re-used in any manner by registered users
of Maelstrom TDBOutline. }
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls, Buttons, ExtCtrls, Menus, DBCtrls,
Grids, Outline, DBOutln, DB, DBTables, Mask, TabNotBk, About, DBGrids,
AEEmp;
type
ETableNotFound = class(Exception);
TfrmMainForm = class(TForm)
pnlSpeedBar: TPanel;
ntbktabDemo: TTabbedNotebook;
tblNotes: TTable;
tblEmployees: TTable;
dtasrcNotes: TDataSource;
dtasrcEmployees: TDataSource;
dtasrcTasks: TDataSource;
pnlNotes: TPanel;
pnlEmployees: TPanel;
pnlTasks: TPanel;
pnlNotesSplitter: TPanel;
pnlEmployeesSplitter: TPanel;
DBOutlineNotes: TDBOutline;
DBOutlineEmployees: TDBOutline;
DBOutlineTasks: TDBOutline;
btnspdAbout: TSpeedButton;
btnspdHelp: TSpeedButton;
tblEmployeesEmpNo: TIntegerField;
tblEmployeesLastName: TStringField;
tblEmployeesFirstName: TStringField;
tblEmployeesPhoneExt: TStringField;
tblEmployeesHireDate: TDateTimeField;
tblEmployeesSalary: TFloatField;
tblEmployeesSupervisor: TIntegerField;
tblEmployeesFullName: TStringField;
bxmemodbNotes: TDBMemo;
grddbEmployees: TDBGrid;
pmnuEmployees: TPopupMenu;
pmnuitemAddChild: TMenuItem;
pmnuitemAddSibling: TMenuItem;
pmnuitemSeparator1: TMenuItem;
pmnuitemDelete: TMenuItem;
pmnuitemEdit: TMenuItem;
pmnuitemSeparator2: TMenuItem;
pnlMoveSplitterNotes: TPanel;
pnlMoveSplitterEmployees: TPanel;
pnlTaskSplitter: TPanel;
pnlMoveSplitterTasks: TPanel;
qryTasks: TQuery;
grddbTasks: TDBGrid;
qryTasksProjectTaskName: TStringField;
qryTasksProjectTaskNumber: TIntegerField;
qryTasksProjectTaskType: TStringField;
qryTasksProjectTaskOrder: TIntegerField;
qryTasksProjectTaskNote: TMemoField;
qryTasksOwningTaskNumber: TIntegerField;
pnlTaskMemo: TPanel;
bxmemodbTasks: TDBMemo;
Memo1: TMemo;
pnlEmployeeFooter: TPanel;
btnSaveDragDropChanges: TButton;
btnCancelDragDropChanges: TButton;
DBNavigatorEmployees: TDBNavigator;
pnlNotesFooter: TPanel;
DBNavigatorNotes: TDBNavigator;
pnlTaskFooter: TPanel;
DBNavigatorTasks: TDBNavigator;
procedure FormCreate(Sender: TObject);
procedure ShowHint(Sender: TObject);
procedure tblEmployeesCalcFields(DataSet: TDataset);
procedure btnspdAboutClick(Sender: TObject);
procedure btnspdHelpClick(Sender: TObject);
procedure DBOutlineEmployeesDragDrop(Sender, Source: TObject; X, Y: Integer);
procedure DBOutlineTasksDragDrop(Sender, Source: TObject; X, Y: Integer);
procedure DBOutlineEmployeesAutoDragDrop(Sender: TObject; var Accept: Boolean;
var FromNode, ToNode: OpenString);
procedure DBOutlineTasksAutoDragDrop(Sender: TObject; var Accept: Boolean;
var FromNode, ToNode: OpenString);
procedure DBOutlineEmployeesMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure pmnuitemAddChildClick(Sender: TObject);
procedure pmnuitemEditClick(Sender: TObject);
procedure pmnuitemDeleteClick(Sender: TObject);
function GetDatabaseName: string;
procedure pnlSplitterMouseDown(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
procedure pnlSplitterMouseMove(Sender: TObject;
Shift: TShiftState; X, Y: Integer);
procedure pnlSplitterMouseUp(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
procedure FormResize(Sender: TObject);
procedure DBOutlineEmployeesDragOver(Sender, Source: TObject; X,
Y: Integer; State: TDragState; var Accept: Boolean);
procedure DBOutlineTasksDragOver(Sender, Source: TObject; X,
Y: Integer; State: TDragState; var Accept: Boolean);
procedure DBOutlineTasksMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure btnSaveDragDropChangesClick(Sender: TObject);
procedure btnCancelDragDropChangesClick(Sender: TObject);
procedure dtasrcNotesDataChange(Sender: TObject; Field: TField);
procedure dtasrcEmployeesDataChange(Sender: TObject; Field: TField);
procedure dtasrcTasksDataChange(Sender: TObject; Field: TField);
end;
var
frmMainForm: TfrmMainForm;
StartSynching: Boolean;
{ the following vars are for use in the splitter bars of the demo program.
they are not related to the use of TDBOutline.}
pnlSendingSplitter: TPanel;
pnlMovingSplitter: TPanel;
otlnedbObjectToResize: TDBOutline;
pnlParentPanel: TPanel;
boolResizeInProgress: Boolean;
FirstLoad: Boolean;
implementation
{$R *.DFM}
{-------------------------------------------------}
procedure TfrmMainForm.FormCreate(Sender: TObject);
var
strDataBaseName: string;
begin
{ the following block of code is used to set up the demo -- not
related to the use of TDBOutline }
Application.OnHint := ShowHint;
Application.HelpFile := 'TDBOutli.hlp';
Application.ShowHint := false;
strDatabaseName := GetDatabaseName;
tblNotes.DatabaseName := strDatabaseName;
tblEmployees.DatabaseName := strDatabaseName;
qryTasks.DatabaseName := strDatabaseName;
if not FileExists(tblNotes.DatabaseName + '\' + tblNotes.TableName) then
raise ETableNotFound.Create('Notes table cannot be located');
if not FileExists(tblEmployees.DatabaseName + '\' + tblEmployees.TableName) then
raise ETableNotFound.Create('Employees table cannot be located');
if not FileExists(qryTasks.DatabaseName + '\' + 'project.db') then
raise ETableNotFound.Create('Project Tasks table cannot be located');
{ to prevent OnDataChange event of the DataSource from
synchronizing the DBOutline during initial load }
StartSynching := false;
{ open the tables/queries -- must be open to execute method LoadFromDataSet }
tblNotes.Open;
tblEmployees.Open;
qryTasks.Open;
{ call method LoadFromDataSet for each dataset: this single method }
{ performs the load of hierarchical data into the outline}
DBOutlineNotes.LoadFromDataSet;
DBOutlineEmployees.LoadFromDataSet;
DBOutlineTasks.LoadFromDataSet;
{Expand the Employee MasterParent, and select the first employee }
if DBOutlineEmployees.ItemCount > 1 then
begin
DBOutlineEmployees.Items[1].Expand;
DBOutlineEmployees.SelectedItem := 2;
end;
{Expand the Task MasterParent, and selecte the first employee }
if DBOutlineTasks.ItemCount > 1 then
begin
DBOutlineTasks.Items[1].Expand;
DBOutlineTasks.SelectedItem := 2;
end;
{ to start OnDataChange event of the DataSources synchronizing
the DBOutline }
StartSynching := true;
{ the following vars used for the panel splitters in the demo
- not related to TDBOutline use.}
pnlMovingSplitter := pnlMoveSplitterNotes;
otlnedbObjectToResize := DBOutlineNotes;
pnlParentPanel := pnlNotes;
FirstLoad := true;
end;
{-------------------------------------------------}
procedure TfrmMainForm.ShowHint(Sender: TObject);
begin
Memo1.Clear;
Memo1.Lines[0] := Application.Hint;
end;
{-------------------------------------------------}
procedure TfrmMainForm.tblEmployeesCalcFields(DataSet: TDataset);
begin
{ this calculated field is used as property DataFieldDisplay in the
Employees example }
tblEmployeesFullName.AsString := tblEmployeesLastName.AsString
+ ', ' + tblEmployeesFirstName.AsString;
end;
{-------------------------------------------------}
procedure TfrmMainForm.btnspdAboutClick(Sender: TObject);
begin
frmAboutBox.ShowModal;
end;
{-------------------------------------------------}
procedure TfrmMainForm.btnspdHelpClick(Sender: TObject);
begin
Application.HelpCommand(HELP_CONTENTS, 0);
end;
{-------------------------------------------------}
procedure TfrmMainForm.DBOutlineEmployeesDragOver(Sender, Source: TObject;
X, Y: Integer; State: TDragState; var Accept: Boolean);
begin
{ for drag-drop in the Employees example }
if Source = DBOutlineEmployees then Accept := true;
end;
{-------------------------------------------------}
procedure TfrmMainForm.DBOutlineTasksDragOver(Sender, Source: TObject; X,
Y: Integer; State: TDragState; var Accept: Boolean);
begin
{ for drag-drop in the Tasks example }
if Source = DBOutlineTasks then Accept := true;
end;
{-------------------------------------------------}
procedure TfrmMainForm.DBOutlineEmployeesDragDrop(Sender, Source: TObject; X,
Y: Integer);
begin
if Source = DBOutlineEmployees then
{ AutoDrop is the single method call required to perform the move
of the node and update the database }
DBOutlineEmployees.AutoDrop(x, y);
end;
{-------------------------------------------------}
procedure TfrmMainForm.DBOutlineTasksDragDrop(Sender, Source: TObject; X,
Y: Integer);
begin
if Source = DBOutlineTasks then
{ AutoDrop is the single method call required to perform the move
of the node and update the database }
DBOutlineTasks.AutoDrop(x, y);
end;
{-------------------------------------------------}
procedure TfrmMainForm.DBOutlineTasksAutoDragDrop(Sender: TObject;
var Accept: Boolean; var FromNode, ToNode: OpenString);
begin
{ The event OnAutoDragDrop occurs just prior to the move of a node via
drag-drop. This line overrides the default confirmation message presented
when a node is dragged-and-dropped. This ability gives the programmer control
over the confirmation message presented to the user. In this case, we
override the default message and have no confirmation message displayed }
Accept := True;
end;
{-------------------------------------------------}
procedure TfrmMainForm.DBOutlineEmployeesAutoDragDrop(Sender: TObject;
var Accept: Boolean; var FromNode, ToNode: OpenString);
var
strMessageText: string;
begin
{ this code overrides the default confirmation message presented when
a node is dragged-and-dropped, replacing it with the custom message.
This ability gives the programmer control over the confirmation
message presented to the user.}
strMessageText := 'This is a custom message defined in the OnAutoDragDrop event of TDBOutline.';
if MessageDlg(strMessageText + ' Have employee ['+FromNode+'] report to ['+ToNode+ ']?'
,mtConfirmation, mbOkCancel,0) = mrOk
then Accept := true
else Accept := false
end;
{-------------------------------------------------}
procedure TfrmMainForm.DBOutlineEmployeesMouseUp(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
{SynchSuccess is a read-only runtime property of TDBOutline -- if true,
the database pointer was successfully synchronized with the selected node.
If false, it was not successfully synchronized. In this example it is used
to hide the DBGrid if the MasterParent node is selected (the MasterParent
not having a corresponding record in the database) }
if DBOutlineEmployees.SynchSuccess then
begin
grddbEmployees.Visible := true;
StartSynching := true;
end
else
begin
grddbEmployees.Visible := false;
StartSynching := false;
end;
end;
{-------------------------------------------------}
procedure TfrmMainForm.DBOutlineTasksMouseUp(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
if DBOutlineTasks.SynchSuccess then
begin
bxmemodbTasks.Visible := true;
grddbTasks.Visible := true;
StartSynching := true;
end
else
begin
bxmemodbTasks.Visible := false;
grddbTasks.Visible := false;
StartSynching := false;
end;
end;
{-------------------------------------------------}
procedure TfrmMainForm.dtasrcNotesDataChange(Sender: TObject;
Field: TField);
begin
{SynchOutline is a TDBOutline method that synchronizes the selected
outline node with the currently selected record. In this case, we
want the selected outline node to re-synch each time the datasource is
notified of any change (i.e., when the record pointer moves). StartSynching is
used in the Demo to prevent the DataSource from synchronizing the
DBOutline during the initial load, AddDBRecords, ChangeDBRecords,
Deletes etc. }
if StartSynching then
DBOutlineNotes.SynchOutline(Self);
end;
{-------------------------------------------------}
procedure TfrmMainForm.dtasrcEmployeesDataChange(Sender: TObject;
Field: TField);
begin
if StartSynching then
DBOutlineEmployees.SynchOutline(Self);
end;
{-------------------------------------------------}
procedure TfrmMainForm.dtasrcTasksDataChange(Sender: TObject;
Field: TField);
begin
if StartSynching then
DBOutlineTasks.SynchOutline(Self);
end;
{-------------------------------------------------}
procedure TfrmMainForm.pmnuitemAddChildClick(Sender: TObject);
var
intParentEmpNo, intNewEmpNo: integer;
begin
StartSynching := false;
{ if popup menu option 'Add Child' was selected}
if Sender = pmnuitemAddChild then
begin
frmAEEmployee.Caption := 'Add Employee as Underling';
intParentEmpNo := tblEmployees.FieldByName('EmpNo').AsInteger;
end
{ else if popup menu option 'Add Sibling' was selected}
else
begin;
frmAEEmployee.Caption := 'Add Employee as Peer';
intParentEmpNo := tblEmployees.FieldByName('Supervisor').AsInteger;
end;
{move to end of table (indexed on EmpNo) and increment last EmpNo by one.}
tblEmployees.Last;
intNewEmpNo := tblEmployees.FieldByName('EmpNo').AsInteger + 1;
tblEmployees.Append;
{ if parent employee number is not 0, i.e. if you are not adding a peer
to a top-level parent }
if intParentEmpNo <> 0 then
tblEmployees.FieldByName('Supervisor').AsInteger := intParentEmpNo;
tblEmployees.FieldByName('EmpNo').AsInteger := intNewEmpNo;
frmAEEmployee.ShowModal;
{ if OK button pressed to add to employee }
if frmAEEmployee.ModalResult=mrOK then
begin
if (tblEmployees.State = dsEdit) or (tblEmployees.State = dsInsert) then
begin
{ Add new employee to database }
tblEmployees.Post;
{ TDBOutline method to add current record (in this case, the new employee)
to the existing outline }
with tblEmployees do
DBOutlineEmployees.AddDBRecord(FieldByName('EmpNo').AsString,
FieldByName('FullName').AsString, FieldByName('Supervisor').AsString);
end;
end
else tblEmployees.Cancel;
if DBOutlineEmployees.SynchSuccess then grddbEmployees.Visible := true
else grddbEmployees.Visible := false;
DBOutlineEmployees.SetFocus;
StartSynching := true;
end;
{-------------------------------------------------}
procedure TfrmMainForm.pmnuitemEditClick(Sender: TObject);
var
OldEmpNo: string;
begin
StartSynching := false;
frmAEEmployee.Caption := 'Edit Employee';
OldEmpNo := tblEmployees.FieldByName('EmpNo').AsString;
frmAEEmployee.ShowModal;
{ if edit changes confirmed with OK button }
if frmAEEmployee.ModalResult=mrOK then
begin
if (tblEmployees.State = dsEdit) or (tblEmployees.State = dsInsert) then
begin
{ post edit changes to database }
tblEmployees.Post;
{ TDBOutline method to reinitialize node corresponding to the
currently selected record (in this case, the edited employee)
with the value of property DataFieldDisplay }
with tblEmployees do
DBOutlineEmployees.ChangeDBRecord(OldEmpNo, FieldByName('EmpNo').AsString,
FieldByName('FullName').AsString);
end;
end
else tblEmployees.Cancel;
DBOutlineEmployees.SetFocus;
StartSynching := true;
end;
{-------------------------------------------------}
procedure TfrmMainForm.pmnuitemDeleteClick(Sender: TObject);
begin
StartSynching := false;
if messagedlg('Delete Employee [' + tblEmployees.FieldByName('FullName').AsString +
']?',mtconfirmation,mbOKCancel,0) = mrOK then
begin
{ !! be sure to delete the Table record first!! If you delete the Outline node
first, then DataAutoSynch will move the datapointer to match the new
DBoutline.SelectedItem, and you'll end up deleting the wrong record! }
tblEmployees.Delete;
DBOutlineEmployees.Delete(DBOutlineEmployees.SelectedItem);
end;
DBOutlineEmployees.SetFocus;
StartSynching := true;
end;
{-------------------------------------------------}
procedure TfrmMainForm.btnSaveDragDropChangesClick(Sender: TObject);
begin
{ this method is used to post all drag-drop changes made to the DBOutline
that are outstanding (i.e., not posted to the dataset). The method
can be used in conjunction with property DataAutoUpdate = false to allow
the user to manipulate the hierarchy without saving, then save or
abandon. }
DBOutlineEmployees.UpdateDraggedNodes(Self);
end;
{-------------------------------------------------}
procedure TfrmMainForm.btnCancelDragDropChangesClick(Sender: TObject);
begin
{ to abandon changes made via drag-drop (see above), if DataAutoUpdate = false,
just re-load the DBOutline. }
DBOutlineEmployees.LoadFromDataSet;
end;
{ ************************************************************************ }
{ the remainder of this code is not related to the use of TDBOutline, but
rather to the functioning of the splitter bars in the demo program }
{-------------------------------------------------}
procedure TfrmMainForm.pnlSplitterMouseDown(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
if ntbktabDemo.PageIndex = 0 then
begin
pnlMovingSplitter := pnlMoveSplitterNotes;
otlnedbObjectToResize := DBOutlineNotes;
pnlParentPanel := pnlNotes;
end;
if ntbktabDemo.PageIndex = 1 then
begin
pnlMovingSplitter := pnlMoveSplitterEmployees;
otlnedbObjectToResize := DBOutlineEmployees;
pnlParentPanel := pnlEmployees;
end;
if ntbktabDemo.PageIndex = 2 then
begin
pnlMovingSplitter := pnlMoveSplitterTasks;
otlnedbObjectToResize := DBOutlineTasks;
pnlParentPanel := pnlTasks;
end;
pnlSendingSplitter := Sender as TPanel;
pnlMovingSplitter.Left := pnlSendingSplitter.Left;
pnlMovingSplitter.Height := pnlSendingSplitter.Height;
pnlMovingSplitter.Visible := true;
boolResizeInProgress := true;
end;
procedure TfrmMainForm.pnlSplitterMouseMove(Sender: TObject;
Shift: TShiftState; X, Y: Integer);
begin
if boolResizeInProgress then
if pnlMovingSplitter.Visible then
pnlMovingSplitter.Left := X + pnlSendingSplitter.Left;
end;
procedure TfrmMainForm.pnlSplitterMouseUp(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
otlnedbObjectToResize.Width := pnlMovingSplitter.Left - otlnedbObjectToResize.Left;
if otlnedbObjectToResize.Width < 5 then otlnedbObjectToResize.Width := 5;
if otlnedbObjectToResize.Width > pnlParentPanel.Width - 20 then
otlnedbObjectToResize.Width := pnlParentPanel.Width - 20;
pnlMovingSplitter.Visible := false;
boolResizeInProgress := false;
end;
procedure TfrmMainForm.FormResize(Sender: TObject);
begin
if FirstLoad then
if otlnedbObjectToResize.Width > pnlParentPanel.Width - 20 then
otlnedbObjectToResize.Width := pnlParentPanel.Width - 20;
Firstload := false;
end;
{-------------------------------------------------}
{used by demo to build database name -- not related to TDBOutline}
function TfrmMainForm.GetDatabaseName: string;
var
ExeDirName,
ExeFileName: array[0..100] of Char;
FileNamePtr: PChar;
NumChars: Word;
begin
StrPCopy(ExeFileName, Application.ExeName);
FileNamePtr := StrRScan(ExeFileName, '\');
NumChars := FileNamePtr - ExeFileName;
StrLCopy(ExeDirName, ExeFileName, NumChars);
Result := StrPas(ExeDirName);
end;
end.